﻿using GN.Pay.Client.Reflection.Meta;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace GN.Pay.Client.Utils
{
    /// <summary>
    /// 反射帮助
    /// </summary>
    public static class ReflectionUtils
    {
        private static ConcurrentDictionary<Type, ISet<MetaMember>> Cache_MetaMembers =
            new ConcurrentDictionary<Type, ISet<MetaMember>>();

        private static ConcurrentDictionary<Type, ISet<MetaProperty>> Cache_MetaPropertys =
           new ConcurrentDictionary<Type, ISet<MetaProperty>>();

        /// <summary>
        /// 获取成员元集合
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public static ISet<MetaMember> GetMetaMembers(Type type)
        {
            ExceptionUtils.CheckNotNull(type, nameof(type));
            ISet<MetaMember> metaMemberys = new HashSet<MetaMember>();
            var ps = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var p in ps)
            {
                metaMemberys.Add(new MetaProperty(p));
            }
            var fs = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
            foreach (var f in fs)
            {
                metaMemberys.Add(new MetaField(f));
            }
            return metaMemberys;
        }

        /// <summary>
        /// 获取字段元集合
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public static ISet<MetaField> GetMetaFields(Type type)
        {
            ExceptionUtils.CheckNotNull(type, nameof(type));
            ISet<MetaField> metaFields = new HashSet<MetaField>();
            var fs = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
            foreach (var f in fs)
            {
                metaFields.Add(new MetaField(f));
            }
            return metaFields;
        }

        /// <summary>
        /// 获取属性元集合
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public static ISet<MetaProperty> GetMetaPropertys(Type type)
        {
            ExceptionUtils.CheckNotNull(type, nameof(type));
            ISet<MetaProperty> metaPropertys = new HashSet<MetaProperty>();
            var ps = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var p in ps)
            {
                metaPropertys.Add(new MetaProperty(p));
            }
            return metaPropertys;
        }

        /// <summary>
        /// 获取缓存的成员元集合
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public static ISet<MetaMember> GetCacheMetaMembers(Type type)
        {
            ExceptionUtils.CheckNotNull(type, nameof(type));
            Lazy<ISet<MetaMember>> lazy = null;
            ISet<MetaMember> metaMembers = Cache_MetaMembers.GetOrAdd(type, (t) =>
            {
                if (lazy == null)
                {
                    lazy = new Lazy<ISet<MetaMember>>(() =>
                    {
                        return GetMetaMembers(t);
                    });
                }
                return lazy.Value;
            });
            return metaMembers;
        }

        /// <summary>
        /// 获取缓存的属性元集合
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public static ISet<MetaProperty> GetCacheMetaPropertys(Type type)
        {
            ExceptionUtils.CheckNotNull(type, nameof(type));
            Lazy<ISet<MetaProperty>> lazy = null;
            ISet<MetaProperty> metaPropertys = Cache_MetaPropertys.GetOrAdd(type, (t) =>
            {
                if (lazy == null)
                {
                    lazy = new Lazy<ISet<MetaProperty>>(() =>
                    {
                        return GetMetaPropertys(t);
                    });
                }
                return lazy.Value;
            });
            return metaPropertys;
        }
    }
}
